#pragma once
#include <iostream>
#include <fstream>
#include <vector>
#include <string>
#include <unistd.h>
#include <sys/types.h>
#include <ctime>
#include <cstdarg>
#include <cstring>
#include <pthread.h>
#include <mutex>


// 日志信息等级
enum LogLevel {
    DEBUG = 1, // 调试
    INFO,      // 信息输出
    WARNING,   // 警告
    ERROR,     // 错误
    FATAL      // 致命错误
};

// 将日志等级转换为字符串
std::string LevelToString(LogLevel level) {
    switch (level) {
    case DEBUG:
        return "DEBUG";
    case INFO:
        return "INFO";
    case WARNING:
        return "WARNING";
    case ERROR:
        return "ERROR";
    case FATAL:
        return "FATAL";
    default:
        return "UNKNOWN";
    }
}

// 日志消息结构体
struct LogMessage {
    std::string level;
    pid_t pid;
    std::string fileName;
    int fileNumber;
    std::string logInfo;
    std::string currentTime;
};

// 打印选项
const int TO_SCREEN = 1;
const int TO_FILE = 2;
const int TIME_BUFF = 128;
const int INFO_BUFF = 1024;

// 日志类
class Log {
private:
    LogMessage logMessage;
    int printChoice;
    std::string printFileName;
    std::mutex logMutex;
    LogLevel miniErrLevel; // 最低错误等级，只打印等于或高于该错误等级的日志信息

    // 获取当前时间
    std::string getCurrentTime() {
        auto now = std::time(nullptr);
        auto time = std::localtime(&now);
        char timeBuff[TIME_BUFF];
        std::snprintf(timeBuff, TIME_BUFF, "%d/%02d/%02d %02d:%02d:%02d",
                      time->tm_year + 1900, time->tm_mon + 1,
                      time->tm_mday, time->tm_hour, time->tm_min, time->tm_sec);
        return timeBuff;
    }

    // 创建日志消息
    void createLogMessage(LogLevel level, const std::string& filename, int filenumber, const char* format, va_list args) {
        if (level < miniErrLevel) {
            return; // 过滤低于最低错误等级的日志信息
        }
        logMessage.level = LevelToString(level);
        logMessage.fileName = filename;
        logMessage.fileNumber = filenumber;
        logMessage.pid = getpid();
        logMessage.currentTime = getCurrentTime();

        char infoBuff[INFO_BUFF];
        std::vsnprintf(infoBuff, INFO_BUFF, format, args);
        logMessage.logInfo = infoBuff;

        flushLog(logMessage);
    }

    // 向屏幕打印日志
    void flushLogToScreen(const LogMessage& lg) {
        std::printf("[%s][%d][%s][%d][%s] %s\n",
                    lg.level.c_str(),
                    lg.pid,
                    lg.fileName.c_str(),
                    lg.fileNumber,
                    lg.currentTime.c_str(),
                    lg.logInfo.c_str());
    }

    // 向文件打印日志
    void flushLogToFile(const LogMessage& lg) {
        std::ofstream out(printFileName, std::ios::app);
        if (out.is_open()) {
            char info[INFO_BUFF];
            std::snprintf(info, sizeof(info), "[%s][%d][%s][%d][%s] %s\n",
                          lg.level.c_str(),
                          lg.pid,
                          lg.fileName.c_str(),
                          lg.fileNumber,
                          lg.currentTime.c_str(),
                          lg.logInfo.c_str());
            out.write(info, std::strlen(info));
            out.close();
        }
    }

    // 刷新日志
    void flushLog(const LogMessage& lg) {
        std::lock_guard<std::mutex> lock(logMutex);
        switch (printChoice) {
        case TO_SCREEN:
            flushLogToScreen(lg);
            break;
        case TO_FILE:
            flushLogToFile(lg);
            break;
        }
    }

public:
    // 构造函数
    Log(int printChoice = TO_SCREEN, const std::string& printFileName = "./log.txt", LogLevel minLevel = DEBUG)
        : printChoice(printChoice), printFileName(printFileName), miniErrLevel(minLevel) {}

    // 记录日志
    void log(LogLevel level, const std::string& filename, int filenumber, const char* format, ...) {
        va_list args;
        va_start(args, format);
        createLogMessage(level, filename, filenumber, format, args);
        va_end(args);
    }

    // 改变日志打印路径
    void changePrintChoice(int newChoice) {
        printChoice = newChoice;
    }

    // 设置最低错误等级
    void setMiniErrLevel(LogLevel level) {
        miniErrLevel = level;
    }

    // 启用输出选项
    void enableOutput(int choice) {
        changePrintChoice(choice);
    }
};

// 全局日志对象
Log lg;

// 日志打印宏
#define INF_LOG(format, ...) lg.log(INFO, __FILE__, __LINE__, format, ##__VA_ARGS__)
#define DBG_LOG(format, ...) lg.log(DEBUG, __FILE__, __LINE__, format, ##__VA_ARGS__)
#define ERR_LOG(format, ...) lg.log(ERROR, __FILE__, __LINE__, format, ##__VA_ARGS__)
#define WRN_LOG(format, ...) lg.log(WARNING, __FILE__, __LINE__, format, ##__VA_ARGS__)
#define FTL_LOG(format, ...) lg.log(FATAL, __FILE__, __LINE__, format, ##__VA_ARGS__)
#define EnableScreen() lg.enableOutput(TO_SCREEN)
#define EnableFILE() lg.enableOutput(TO_FILE)
